#!/usr/bin/python

import collections
import datetime
import dateutil.parser as dateutil_parser
import fileinput
import optparse
import re
import sys
import time
import textwrap

attendee_map = dict(Avalena="Valen", Pansy="Paisley", Passia="Paisley", Seaohex="Doomy")

class Raid(object):
  def __init__(self, start_time):
    self.start_time = start_time
    self.attendees = collections.defaultdict(int)
    self.wrapper = textwrap.TextWrapper(initial_indent='   ', subsequent_indent='   ')

  def AttendeeTick(self, attendee, amount, force=False):
    attendee = attendee_map.get(attendee, attendee)
    if amount < 5000 or force:
      self.attendees[attendee] += amount

  def Report(self):
    sorted_attendees = self.attendees.keys()
    if not sorted_attendees: return
    sorted_attendees.sort(lambda a, b: cmp(self.attendees[a], self.attendees[b]) or cmp(b, a), reverse=True)
    attendee_string = " ".join("%s(%d)" % (a, self.attendees[a]) for a in sorted_attendees)
    print "Raid at %s:" % self.start_time
    print "\n".join(self.wrapper.wrap(attendee_string))

  def MergeFrom(self, other):
    for a, v in other.attendees.items():
      a = attendee_map.get(a, a)
      self.AttendeeTick(a, v, force=True)

  def Date(self):
    return self.start_time.strftime("%Y-%m-%d")

def main(args):
  parser = optparse.OptionParser(__doc__)
  parser.add_option("-s", "--start-date", help="raid to start from")
  parser.add_option("-e", "--end-date", help="raid to end at")
  parser.add_option("", "--csv", help="file to save CSV output to")
  options, args = parser.parse_args(args)

  basic_line_re = re.compile(r'(\d{1,2})/(\d{1,2})  *(\d\d):(\d\d):(\d\d)\.(\d+) *(.*)$')
  award_re = re.compile(r'(?:\S+): EPGP: ([+-]\d+) EP \(.*?\) to *(.*)$')
  continue_re = re.compile(r'(?:\S+): EPGP: ((\w+, )+(\w+)) *$')
  tmptime = time.localtime()
  year, dst = tmptime[0], tmptime[-1]

  last_epoch_time = None
  last_award_epoch = 0
  raid_start = None
  last_amount = 0
  current_raid = None
  master_raid = Raid("Overall")
  start_date = None
  if options.start_date:
    start_date = dateutil_parser.parser().parse(options.start_date)
  end_date = None
  if options.end_date:
    end_date = dateutil_parser.parser().parse(options.end_date)

  all_raids = dict()  # YYYY-MM-DD -> raid
  for line in fileinput.input(args):
    line = line.strip().rstrip(",")
    if not line: continue
    if "EPGP:" not in line: continue
    m = basic_line_re.match(line)
    if m is None:
      print >>sys.stderr, "Unparseable: %s" % line
      continue

    # Handle time
    epoch_time = time.mktime((year, int(m.group(1)), int(m.group(2)),
                              int(m.group(3)), int(m.group(4)), int(m.group(5)),
                              0, 0, dst)) + int(m.group(6))/1000.0
    time_object = datetime.datetime(year, int(m.group(1)), int(m.group(2)),
                                    int(m.group(3)), int(m.group(4)), int(m.group(5)),
                                    1000 * int(m.group(6)))
    if start_date and time_object < start_date:
      continue
    if end_date and time_object > end_date:
      continue

    if last_epoch_time is None:
      last_epoch_time = epoch_time

    delta = epoch_time - last_epoch_time
    if delta > 8 * 60 * 60 or current_raid is None:
      if current_raid is not None:
        current_raid.Report()
        master_raid.MergeFrom(current_raid)
        all_raids[current_raid.Date()] = current_raid
      current_raid = Raid(time_object)
  
    # Handle content
    content = m.group(7)

    m1 = award_re.search(content)
    m2 = continue_re.search(content)
    if m1:
      amount = int(m1.group(1))
      last_amount = amount
      for attendee in m1.group(2).split(", "):
        current_raid.AttendeeTick(attendee, amount)
      last_award_epoch = epoch_time
    elif m2 and abs(epoch_time - last_award_epoch) < 2 and last_amount:
      for attendee in m2.group(1).split(", "):
        current_raid.AttendeeTick(attendee, last_amount)
    else:
      print >>sys.stderr, "Unparseable line: %s" % content
      
    last_epoch_time = epoch_time

  all_raids[current_raid.Date()] = current_raid
  master_raid.MergeFrom(current_raid)
  current_raid.Report()

  print
  print "Overall Attendance:"
  master_raid.Report()
    
  if options.csv:
    f = open(options.csv, "w")
    sorted_raids = sorted(all_raids.keys(), reverse=True)
    first_row = [ "Player" ] + sorted_raids
    print >>f, ",".join(first_row)

    for player in sorted(master_raid.attendees.keys()):
      row = [ player ]
      for day in sorted_raids:
        raid = all_raids[day]
        ep = raid.attendees.get(player, 0)
        row.append("%d" % ep)
      print >>f, ",".join(row)
    

if __name__ == '__main__':
  main(sys.argv[1:])
